package os_listener;

import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URL;

import GUI.Encoder;

/**
 * this class get updates from the server and perform them
 */
public class UpdatesFromServer implements Runnable
{
	//flags for updating the state of the service
	Boolean stop;
	Boolean pause;
	//private String host = "localhost"; // or ip address
	// this is an example in a comment about how you can enter an ip address
	private String host = "10.0.0.1";
	private ObjectInputStream in;
	private String userName;
	private String path;
	Encoder e;

	
	@Override
	/**
	 * the Thread run function that execute this class's work
	 */
	public void run() 
	{
		String connectionUrl = "http://"+host+":8080/serverManager.ConnectionWithSpy?user_name="+userName;
		Socket socket=null;
		URL url;
		BufferedReader in2;
		// as long as the service is open
		while(stop==false)
		{
			try
			{
				url = new URL(connectionUrl.toString());
				// connecting to the server
				in2 = new BufferedReader(new InputStreamReader(url.openStream()));
				// an update arrived
				in2.close();

				// the case that the service stopped working
				if (stop==true)
				{
					break;
				}
				
				socket = null;
				socket = new Socket(host,7777);
				new PrintWriter(socket.getOutputStream(),true);
				in = new ObjectInputStream(socket.getInputStream());
				
				// getting the update
				ServerUpdates su = (ServerUpdates) in.readObject();
				
				// the case that the update is sharing a folder
				if(su.getUpdate().equals("sharing folder"))
				{
					String dir_name = su.getDir_name();
					File f = new File(path + "\\" + dir_name);
					OS_Listener.getInstance().setShared_folder(true);
					// creating the directory
					f.mkdir();
					in = new ObjectInputStream(socket.getInputStream());
					su = (ServerUpdates) in.readObject();
					byte[] bytes;
					// as long as there are more files in the directory
					while(!su.getUpdate().equals("the end"))
					{
						// the case that there is a file in the directory
						if(su.getUpdate().equals("recover file from dir"))
						{
							// getting the file
							bytes = su.getBytes();
							// the case that the file was accepted
							if(bytes != null)
							{
								OS_Listener.getInstance().setShared_folder(true);
								// creating the file
								convByteToFile(bytes, path + "\\" + dir_name + "\\" + su.getFile_name());
								// tagging the file
								OS_Listener.getInstance().tagSharedFiles(true, su.getFile_name(), path + "\\" + dir_name + "\\" + su.getFile_name());
							}
						}
						in = new ObjectInputStream(socket.getInputStream());
						su = (ServerUpdates) in.readObject();
						// the case that something went wrong
						if(su == null)
						{
							System.out.println("transfering problem");
							break;
						}
					}
				}
				// the case that the update is getting a new file from a shared folder
				if(su.getUpdate().equals("new file in shared folder"))
				{
					// getting the file
					byte[] bytes = su.getBytes();
					// the case that the file was accepted
					if(bytes != null)
					{
						OS_Listener.getInstance().setShared_folder(true);
						// creating the file
						convByteToFile(bytes, path + "\\" + su.getDir_name() + "\\" + su.getFile_name());
						// tagging the file
						OS_Listener.getInstance().tagSharedFiles(true, su.getFile_name(), path + "\\" + su.getDir_name() + "\\" + su.getFile_name());
					}
					in = new ObjectInputStream(socket.getInputStream());
					su = (ServerUpdates) in.readObject();
					// the case that something went wrong
					if(su == null || !su.getUpdate().equals("the end"))
					{
						System.out.println("transfering problem");
						break;
					}
				}
				// the case that the update is a file deleted from a shared folder
				if(su.getUpdate().equals("delete file from shared folder"))
				{
					File f = new File(path + "\\" + su.getDir_name() + "\\" + su.getFile_name());
					OS_Listener.getInstance().setShared_folder(true);
					// deleting the file
					f.delete();
					// removing the file tags
					OS_Listener.getInstance().tagSharedFiles(false, su.getFile_name(), path + "\\" + su.getDir_name() + "\\" + su.getFile_name());
					in = new ObjectInputStream(socket.getInputStream());
					su = (ServerUpdates) in.readObject();
					// the case that something went wrong
					if(su == null || !su.getUpdate().equals("the end"))
					{
						System.out.println("transfering problem");
						break;
					}
				}
			}
			catch(Exception e) {}
		}
	}
	
	/**
	 * A handle to the unique UpdatesFromServer instance.
	 */
	static private UpdatesFromServer instance = null;
	//for the singleton
	private static Object someObject=new Object();
	
	// the private constructor of this class
	private UpdatesFromServer()
	{
		stop=true;
		pause=false;
		XMLDecoder d;
		try 
		{
			d = new XMLDecoder(new BufferedInputStream(new FileInputStream("C:/Program Files/m&l_dropbox/details.xml")));
			e = (Encoder) d.readObject();
			d.close();
			userName = e.getUserName();
			path = e.getPath() + "\\DropBox";
		}
		catch (FileNotFoundException e1) 
		{
			e1.printStackTrace();
		}
	}
	
	 /**
	 * @return The unique instance of this class.
	 */
	static public UpdatesFromServer getInstance()
	{
		if(null == instance) 
		{
			//to insure that the time slice doesn't cause the creation of 2 instances
			synchronized (someObject) 
			{
				if (null == instance)
					instance = new UpdatesFromServer();
			}
		}
	    return instance;
	}
	
	//getters and setters
	
	public Boolean getStop() 
	{
		return stop;
	}

	public void setStop(Boolean stop) throws IOException 
	{
		this.stop = stop;
	}
	
	// convert a bytes array to a file in a given destination - taken from the web
	private File convByteToFile(byte[] bytes, String path)
	{ 
		File newFile = new File(path);
		FileOutputStream fos = null;

		try 
		{
			fos = new FileOutputStream(newFile);
			fos.write(bytes);
			fos.flush();
			fos.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}      

		return newFile;
	}
}
